#pragma once




#include "qstring.h"
#include "qrect.h"
using namespace micro::utils;

#include "qpen.h"
#include "qbrush.h"
#include "qbitmap.h"
#include "qfont.h"
#include "qregion.h"



namespace micro
{
namespace gui
{


class QWindow ;
class QGraphics
{
protected:
    HDC hdc;


public:
    QGraphics( HDC h = nullptr )
    {
        hdc = h;
    }
    virtual ~QGraphics( void )
    {
        if ( hdc )
            ::DeleteDC( hdc );

        hdc = nullptr;
    }

    inline operator HDC()
    {
        return hdc;
    }
    HDC GetHandle()
    {
        return hdc;
    }
    HDC Detach()
    {
        HDC hDC = hdc;
        hdc = nullptr;
        return hDC;
    }

    HGDIOBJ SelectObject( HGDIOBJ hObject )
    {
        return ::SelectObject( hdc, hObject );
    }
    int  Save()
    {
        return ::SaveDC( hdc );
    }
    void Restore( int state )
    {
        ::RestoreDC( hdc, state );
    }

    void SetMapMode( int imode = MM_TEXT )
    {
        ::SetMapMode( hdc, imode );
    }
    void SetViewportOrg( int x, int y )
    {
        ::SetViewportOrgEx( hdc, x, y, nullptr );
    }
    //void SetViewportExt(int x, int y){::SetViewportExtEx(hdc,x,y,nullptr); }//for MM_ISOTROPIC
    //void SetWindowExt(int x, int y){ ::SetWindowExtEx(hdc, x,y,nullptr);   }//MM_ISOTROPIC

public:

    void MoveTo( int cx, int cy );
    void LineTo( int cx, int cy );
    void Rectangle( const QRect & r );
    void RoundRect( const QRect & r, int w, int h );
    void ExtTextOut( LPCTSTR str, const QRect  & rc,  QCOLOR clr, UINT fuOptions = ETO_OPAQUE, int x = 0, int y = 0 );
    void ExtTextOut( LPCTSTR str, int count, const QRect  & rc,  QCOLOR clr, UINT fuOptions = ETO_OPAQUE, int x = 0, int y = 0 );


    int  DrawText( const QString & str, QRect  & rect, UINT mode = DT_VCENTER | DT_CENTER | DT_SINGLELINE );
    int  DrawText( LPCTSTR str, QRect & rect, UINT mode = DT_VCENTER | DT_CENTER | DT_SINGLELINE );
    void DrawEdge( QRect & r, UINT nEdge, UINT flags );
    void DrawIcon( int x, int y,  HICON  icon )
    {
        ::DrawIconEx( hdc, x, y, icon, 0, 0 , 0, 0,  DI_NORMAL );
    }



public:
    void Draw3dRect( QRect & , QCOLOR colorTopLeft, QCOLOR colorBottomRight );
    void DrawFrameControl( QRect & rc, UINT type, UINT state )
    {
        ::DrawFrameControl( hdc, rc, type, state );
    }
    void FillSolidRect( const QRect & , QCOLOR clr );


    QCOLOR SetTextColor( QCOLOR color )
    {
        return ::SetTextColor( hdc, color );
    }
    int   SetBkMode( int mode )
    {
        return ::SetBkMode( hdc, mode );
    }
    QCOLOR SetBkColor( QCOLOR color )
    {
        return ::SetBkColor( hdc, color );
    }


    //QCOLOR SetPenColor(QCOLOR color){		return ::SetDCPenColor (hdc, color);}
    //QCOLOR SetBrushColor(QCOLOR color){		return ::SetDCBrushColor (hdc, color);}

    void DrawFocusRect( const QRect  & rc )
    {
        ::DrawFocusRect( hdc, &rc );
    }
    bool GetTextExtentPoint32( const QString & str , QSize & sz )
    {
        return 0 != ::GetTextExtentPoint32( hdc, str, str.GetLength(), &sz );
    }


    bool BitBlt( int x, int y, int cx, int cy, HDC hhh, int x1, int y1, DWORD rop )
    {
        ASSERT( hhh );
        return 0 != ::BitBlt( hdc, x, y, cx, cy, hhh, x1, y1, rop );
    }
    bool BitBlt( int x, int y, int cx, int cy, QGraphics * src, int x1, int y1, DWORD rop )
    {
        ASSERT( src );
        return 0 != ::BitBlt( hdc, x, y, cx, cy, *src, x1, y1, rop );
    }
    bool BitBlt( QRect & rc, QGraphics * src, int x1, int y1, DWORD rop )
    {
        ASSERT( src );
        return 0 != ::BitBlt( hdc, rc.left, rc.top, rc.Width(), rc.Height(), *src, x1, y1, rop );
    }

    void CreateCompatible( QGraphics * p )
    {
        hdc = ::CreateCompatibleDC( *p );
        //m_bDestroy = true;
    }
    void CreateCompatible( HDC h )
    {
        hdc = ::CreateCompatibleDC( h );
        //m_bDestroy = true;
    }

    int GetClipBox( QRect * pRect )
    {
        return ::GetClipBox( hdc, pRect );
    }
    int IntersectClipRect( QRect r )
    {
        //if (IsValidHandle())
        return ::IntersectClipRect( hdc, r.left, r.top, r.right, r.bottom );
        //return 0;
    }
    int ExcludeClipRect( QRect r )
    {
        //if (IsValidHandle())
        return ::ExcludeClipRect( hdc, r.left, r.top, r.right, r.bottom );
        //return 0;
    }
    int GetDeviceCaps( int index )
    {
        return ::GetDeviceCaps( hdc, index );
    }

//#if (!defined(_WIN32_WCE) || (_WIN32_WCE >= 420))
//bool QGraphics::GradientFill(const PTRIVERTEX pVertices, DWORD nVertices, void* pMeshElements, DWORD nMeshElements, DWORD dwMode);
//#endif

    void FillRect( QRect & lprc,   QBrush * pBruhs );
    void FillRect( QRect & lprc,   HBRUSH hBruhs );
    void FrameRect( QRect & lpRect, HBRUSH hBrush );

};


class QSelector
{
    // No copy constructor.
    //_NO_COPY( QSelector );
public:
    // Constructor. Select the object
    // into a device context.
    QSelector( QGraphics * pDC, HGDIOBJ hObject )
    {
        // Save the DC.
        m_pDC = pDC;

        // Select the object saving the current
        // object.
        if ( pDC )
            m_hObject = pDC->SelectObject( hObject );
    }
    QSelector( QGraphics & dc, HGDIOBJ hObject )
    {
        // Save the DC.
        m_pDC = &dc;

        // Select the object saving the current
        // object.

        m_hObject = dc.SelectObject( hObject );
    }

    // Destructor. Restores the old object.
    ~QSelector()
    {
        // Only if this one is valid.
        if ( m_pDC )
            m_pDC->SelectObject( m_hObject );
    }

protected:
    // Data.
    QGraphics * m_pDC;
    HGDIOBJ	m_hObject;
};




class QCompatibleGraphics: public QGraphics
{
    QBitmap		bmp;
    HGDIOBJ		oldbmp;

public:
    QCompatibleGraphics()//:QGraphics()
    {
    }
    // Constructor.
    QCompatibleGraphics( QGraphics * p, int cx, int cy )
    {
        Create( *p, cx, cy );
    }
    QCompatibleGraphics( HDC hh, int cx, int cy )
    {
        Create( hh, cx, cy );
    }


    void Create( HDC hdc0, int cx, int cy )
    {
        ASSERT( hdc0 );
        hdc = ::CreateCompatibleDC( hdc0 );

        bmp.CreateCompatibleBitmap( hdc0, cx, cy );
        oldbmp = SelectObject( bmp );
    }


    // Destructor.
    ~QCompatibleGraphics()
    {
        // Only if this one is valid.
        if ( hdc )
        {
            SelectObject( oldbmp );
// 			::DeleteDC(hdc);
// 			hdc = nullptr;
        }
    }

    QBitmap  &  GetBitmap()
    {
        return bmp;
    }


    int  GetDIBits( UINT uStartScan, UINT cScanLines, LPVOID lpvBits, LPBITMAPINFO lpbi,  UINT uUsage )
    {
        return  bmp.GetDIBits( hdc, uStartScan, cScanLines, lpvBits, lpbi, uUsage );
    }

};



class QPaintGraphics : 	public QGraphics
{
protected:
    PAINTSTRUCT ps;
    HWND hwnd;

public:
    QPaintGraphics( QWindow * p );
    virtual ~QPaintGraphics( void );
    QRect	GetPaintRect();
};


class QClientGraphics : public QGraphics
{
protected:
    HWND hwnd;

public:
    QClientGraphics( QWindow * p = nullptr );

    virtual ~QClientGraphics( void );
    void    CreateGraphics( QWindow * p ) ;
};






class QWindowGraphics : public QGraphics
{
protected:
    HWND hwnd;
public:
    QWindowGraphics( QWindow * p );
    virtual ~QWindowGraphics();
};



//for double buffering
class QMemoryGraphics : public QGraphics
{
protected:
// Data members
    QGraphics	* m_hDCOriginal;
    QRect		m_rcPaint;
    QBitmap		m_bmp;
    HGDIOBJ		m_hBmpOld;

public:
    QMemoryGraphics( QGraphics * pdc, QRect & rcPaint ) : m_hDCOriginal( pdc ), m_hBmpOld( nullptr )
    {
        m_rcPaint = rcPaint;
        CreateCompatible( m_hDCOriginal );

        //ASSERT(hdc != nullptr);
        m_bmp.CreateCompatibleBitmap( *m_hDCOriginal, m_rcPaint.Width(), m_rcPaint.Height() );

        //ASSERT(m_bmp.m_hBitmap != nullptr);

        m_hBmpOld = SelectObject( m_bmp );
        SetViewportOrg( -m_rcPaint.left, -m_rcPaint.top );
    }



    virtual ~QMemoryGraphics()
    {
        m_hDCOriginal->BitBlt(  m_rcPaint, this, m_rcPaint.left, m_rcPaint.top, SRCCOPY );
        SelectObject( m_hBmpOld );

        if ( hdc )
            DeleteDC( hdc );
    }
};








}
}//micro